var util = require('util');
var sys = require('sys');
var fs = require('fs');
var Parser = require("jison").Parser;

var grammar = {
	
	lex : {
		rules : [
			['[ \t]+',		""],
			['[\\n\\r;]+',		"return ';';"],
			['[0-9]+',		"return 'NUM';"],
			['\\+',			"return '+';"],
			['\\.',			"return 'CONCAT';"],
			['\\-',			"return '-';"],
			['\\*',			"return '*';"],
			['\\/',			"return '/';"],
			['\\(',			"return '(';"],
			['\\)',			"return ')';"],
			[',',			"return ',';"],
			['>=',			"return '>=';"],
			['<=',			"return '<=';"],
			['<>',			"return '<>';"],
			['>',			"return '>';"],
			['<',			"return '<';"],
			['=',			"return '=';"],
			['"[^"]*"',			"return 'STR';"],
			['BEGIN',			"return 'BEGIN';"],
			['ENDIF',			"return 'ENDIF';"],
			['WEND',			"return 'WEND';"],
			['END',			"return 'END';"],
			['INPUT',			"return 'INPUT';"],
			['PRINT',			"return 'PRINT';"],
			['SELECT',			"return 'SELECT';"],
			['WHILE',			"return 'WHILE';"],
			['IF',			"return 'IF';"],
			['THEN',			"return 'THEN';"],
			['ELSE',			"return 'ELSE';"],
			['GOTO',			"return 'GOTO';"],
			['LET',			"return 'LET';"],
			['[a-zA-Z][a-zA-Z0-9]*',	"return 'IDENT';"],
			['@[a-zA-Z][a-zA-Z0-9]*',	"return 'LABEL';"],
			['$',			"return 'EOF';"],
		]
	},
	operators : [
		['left', 'INPUT', 'PRINT', 'SELECT'],
		['left', ',', '=', '<', '>', '<=', '>=', '<>'],
		['left', '+', '-', 'CONCAT'],
		['left', '*', '/'],
		['left', 'IF', 'THEN', 'ELSE', 'GOTO', 'LET'],
		['left', ';'],
	],
    bnf: {
		Program : [
			['StatementList EOF', '$1[1].root = true; return $1;'],
		],
		StatementList : [
			['; StatementList', '$$ = $2;'],
			['Statement ;', '$$ = ["STLIST", {items:[$1]}];'],
			['StatementList Statement ;', '$1[1].items.push($2); $$ = $1;'],
		],
		Statement : [
			['BEGIN StatementList END', '$$ = $2;'],
			['BEGIN ; StatementList END', '$$ = $3;'],
			['BEGIN ; StatementList ; END', '$$ = $3;'],
			['BEGIN StatementList ; END', '$$ = $2;'],
			['LABEL Statement', '$2[1].label = $1; $$ = $2;'],
			['Exp', '$$ = ["ST_EXP", {exp:$1}];'],
			['If_Statement', '$$ = $1;'],
			['While_Statement', '$$ = $1;'],
			['GOTO LABEL', '$$ = ["ST_GOTO", {dest:$2}];'],
			['LET IDENT = Exp', '$$ = ["ST_LET", {l:["VAR", {name:$2}], r:$4}];'],
		],
		If_Statement : [
			['IF Exp THEN StatementList ENDIF', '$$ = ["ST_IF", {cond:$2, then:$4}];'],
			['IF Exp THEN StatementList ELSE StatementList ENDIF', '$$ = ["ST_IF", {cond:$2, then:$4, else:$6}];'],
		],
		While_Statement : [
			['WHILE Exp StatementList WEND', '$$ = ["ST_WHILE", {cond:$2, body:$3}];']
		],
		Exp : [
			['NUM',				'$$ = ["INT", {value:parseInt($1)}];'],
			['STR',				'$$ = ["STR", {value:String($1)}];'],
			['Exp + Exp',		'$$ = ["ADD", {l:$1, r:$3}];'],
			['Exp CONCAT Exp',		'$$ = ["CONCAT", {l:$1, r:$3}];'],
			['Exp - Exp',		'$$ = ["SUB", {l:$1, r:$3}];'],
			['Exp * Exp',		'$$ = ["MUL", {l:$1, r:$3}];'],
			['Exp / Exp',		'$$ = ["DIV", {l:$1, r:$3}];'],
			['Exp = Exp',		'$$ = ["EQ", {l:$1, r:$3}];'],
			['Exp > Exp',		'$$ = ["GT", {l:$1, r:$3}];'],
			['Exp < Exp',		'$$ = ["LT", {l:$1, r:$3}];'],
			['Exp >= Exp',		'$$ = ["GE", {l:$1, r:$3}];'],
			['Exp <= Exp',		'$$ = ["LE", {l:$1, r:$3}];'],
			['Exp <> Exp',		'$$ = ["NE", {l:$1, r:$3}];'],
			['( Exp )',			'$$ = $2;'],
			['IDENT',			'$$ = ["VAR", {name:$1}];'],
			['IDENT ( List )', 	'$$ = ["CALL", {func:$1, args:$3}];'],
			['IDENT ( )', 	'$$ = ["CALL", {func:$1}];'],
			['INPUT Exp', '$$ = ["CALL", {func:"INPUT", args:["LIST", {items:[$2]}]}];'],
			['PRINT List', '$$ = ["CALL", {func:"PRINT", args:$2}];']
		],
		List : [
			['Exp', '$$ = ["LIST", {items:[$1]}];'],
			['List , Exp', '$1[1].items.push($3); $$ = $1;'],
		]
    }
};

var parser = new Parser(grammar);
var source = parser.generate();
fs.writeFile('qubic-grammar.js', source, function (err) {
	if(err) {
		throw err;
	}
	console.log('Parser generated');
});

var prog = 'LET a = 1; WHILE a <= 10; PRINT a; LET a = a + 1; WEND;';

sys.puts(util.inspect(parser.parse(prog), false, 100));
